package com.biz.redis.util;

import com.biz.redis.exception.*;
import org.apache.commons.lang.*;
import org.springframework.stereotype.*;

import javax.annotation.*;
import java.util.concurrent.*;

/**
 * @Description
 *  redis分布式锁
 *  使用场景：
 *      1.任务调度
 *      2.操作同一个数据
 * @Author liuxi
 * @Date 2024/4/21
 **/
@Component
public class RedisShareLockUtil {

    @Resource
    private RedisUtil redisUtil;

    /**
     * 加锁
     *
     * @param lockKey key
     * @param requestId requestId
     * @param time 加锁时长
     */
    public boolean lock(String lockKey, String requestId, Long time) {
        // 1.参数的校验
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId) || time <= 0) {
            throw new ShareLockException("分布式锁-加锁参数异常");
        }
        long currentTime = System.currentTimeMillis();
        final long timeOut = 1000L;
        long outTime = currentTime + timeOut;
        // 2.加锁可以自旋
        while (currentTime < outTime) {
            // 3.借助redis的setnx来进行锁的设置
            boolean result = redisUtil.setNx(lockKey, requestId, time, TimeUnit.MILLISECONDS);
            if (result) {
                return true;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            currentTime = System.currentTimeMillis();
        }
        return false;
    }

    /**
     * 解锁
     */
    public boolean unLock(String lockKey, String requestId) {
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId)) {
            throw new ShareLockException("分布式锁-解锁参数异常");
        }
        try {
            String value = redisUtil.get(lockKey);
            if (requestId.equals(value)) {
                redisUtil.del(lockKey);
                return true;
            }
        } catch (Exception e) {
            // 补日志
        }
        return false;
    }

    /**
     * 尝试加锁
     * 拿不到锁直接返回
     */
    public boolean tryLock(String lockKey, String requestId, Long time) {
        if (StringUtils.isBlank(lockKey) || StringUtils.isBlank(requestId) || time <= 0) {
            throw new ShareLockException("分布式锁-尝试加锁参数异常");
        }
        return redisUtil.setNx(lockKey, requestId, time, TimeUnit.MILLISECONDS);
    }

}
